/**
 * @description 向量类
 * @author hzq
 * @date 2025-04-11 17:02:38
 * @copyright Copyright (c) 2025 by hzq, All Rights Reserved.
 */
class Vector {
  // 定义一个受保护的数组，用于存储向量的数据
  protected _data: number[];
  // 构造函数，接受任意数量的参数，并将它们存储在_data数组中
  constructor(...args: number[]) {
    this._data = [...args];
  }

  /**
   * #### 获取向量的维度
   */
  get dimension() {
    return this._data.length;
  }

  /**
   * #### 获取向量的范数
   */
  get norm() {
    return Math.hypot(...this._data);
  }

  /**
   * #### 获取向量的某个元素
   * @param index 向量的索引
   * @returns
   */
  getItem(index: number) {
    return this._data[index];
  }

  /**
   * #### 归一化向量
   * @returns
   */
  normalize() {
    // 如果向量的范数为0，则抛出错误
    if (this.norm === 0) {
      throw new Error("Cannot normalize a zero vector");
    }
    // 将向量的每个元素除以范数，得到归一化后的向量
    const data = this._data.map((item) => item / this.norm);
    return new Vector(...data);
  }

  /**
   * #### 向量与数相乘
   * @param k 倍数
   * @returns
   */
  mul(k: number) {
    // 将向量的每个元素乘以数k，得到乘积向量
    return new Vector(...this._data.map((item) => item * k));
  }

  /**
   * #### 向量相加
   * @param v 向量
   * @returns
   */
  add(v: Vector) {
    // 如果两个向量的维度不同，则抛出错误
    if (this.dimension !== v.dimension) {
      throw new Error("Cannot add vectors of different dimensions");
    }
    // 将两个向量的对应元素相加，得到和向量
    const sums = this._data.map((item, index) => item + v.getItem(index));
    return new Vector(...sums);
  }

  /**
   * #### 向量相减
   * @param v 向量
   * @returns
   */
  sub(v: Vector) {
    // 如果两个向量的维度不同，则抛出错误
    if (this.dimension !== v.dimension) {
      throw new Error("Cannot subtract vectors of different dimensions");
    }
    // 将两个向量的对应元素相减，得到差向量
    const diffs = this._data.map((item, index) => item - v.getItem(index));
    return new Vector(...diffs);
  }

  /**
   * #### 向量的点积
   * @param v 向量
   * @returns
   */
  dot(v: Vector) {
    // 如果两个向量的维度不同，则抛出错误
    if (this.dimension !== v.dimension) {
      throw new Error("Cannot dot product vectors of different dimensions");
    }
    // 将两个向量的对应元素相乘，并求和，得到点积
    const dotProduct = this._data.reduce((acc, item, index) => {
      return acc + item * v.getItem(index);
    }, 0);
    return dotProduct;
  }

  /**
   * #### 向量的正向量
   * @returns
   */
  pos() {
    // 将向量的每个元素乘以1，得到正向量
    return this.mul(1);
  }

  /**
   * #### 向量的负向量
   * @returns
   */
  neg() {
    // 将向量的每个元素乘以-1，得到负向量
    return this.mul(-1);
  }

  /**
   * #### 生成一个指定维度的零向量
   * @param dim 向量的维度
   * @returns
   */
  static zero(dim: number) {
    // 使用Array.fill()方法生成一个指定维度的数组，并将所有元素填充为0
    return new Vector(...Array(dim).fill(0));
  }

  /**
   * #### 将向量转换为字符串
   * @returns
   */
  toString() {
    let str = "";
    // 遍历向量的每个元素，并将其转换为字符串
    for (let i = 0, len = this._data.length; i < len; i++) {
      str += this._data[i];
      // 如果不是最后一个元素，则在元素之间添加逗号和空格
      if (i !== len - 1) {
        str += ", ";
      }
    }
    // 返回向量的字符串表示
    return `Vector(${str})`;
  }
}

// 导出Vector类
export default Vector;
